我們可以使用 v-for 指令基於一個數組來渲染一個列表。v-for 指令的值需要使用 item in items 形式的特殊語法,其中 items 是源數據的數組,而 item 是迭代項的別名:
const items = ref([{ message: 'Foo' }, { message: 'Bar' }])
<li v-for="item in items">
{{ item.message }}
</li>
在 v-for 塊中可以完整地訪問父作用域內的屬性和變量。v-for 也支持使用可選的第二個參數表示當前項的位置索引。
const parentMessage = ref('Parent')
const items = ref([{ message: 'Foo' }, { message: 'Bar' }])
<li v-for="(item, index) in items">
{{ parentMessage }} - {{ index }} - {{ item.message }}
</li>
v-for 變量的作用域和下面的 JavaScript 代碼很類似:
const parentMessage = 'Parent'
const items = [
/* ... */
]
items.forEach((item, index) => {
// 可以訪問外層的 `parentMessage`
// 而 `item` 和 `index` 只在這個作用域可用
console.log(parentMessage, item.message, index)
})
注意 v-for 是如何對應 forEach 回調的函數簽名的。實際上,你也可以在定義 v-for 的變量別名時使用解構,和解構函數參數類似:
<li v-for="{ message } in items">
{{ message }}
</li>
<!-- 有 index 索引時 -->
<li v-for="({ message }, index) in items">
{{ message }} {{ index }}
</li>
對於多層嵌套的 v-for,作用域的工作方式和函數的作用域很類似。每個 v-for 作用域都可以訪問到父級作用域:
<li v-for="item in items">
<span v-for="childItem in item.children">
{{ item.message }} {{ childItem }}
</span>
</li>
你也可以使用 of 作為分隔符來替代 in,這更接近 JavaScript 的迭代器語法:
<div v-for="item of items"></div>
你也可以使用 v-for 來遍歷一個對象的所有屬性。遍歷的順序會基於對該對象調用 Object.keys() 的返回值來決定。
const myObject = reactive({
title: 'How to do lists in Vue',
author: 'Jane Doe',
publishedAt: '2016-04-10'
})
<ul>
<li v-for="value in myObject">
{{ value }}
</li>
</ul>
可以通過提供第二個參數表示屬性名 (例如 key):
<li v-for="(value, key) in myObject">
{{ key }}: {{ value }}
</li>
第三個參數表示位置索引:
<li v-for="(value, key, index) in myObject">
{{ index }}. {{ key }}: {{ value }}
</li>
v-for 可以直接接受一個整數值。在這種用例中,會將該模板基於 1...n 的取值範圍重複多次。
<span v-for="n in 10">{{ n }}</span>
注意此處 n 的初值是從 1 開始而非 0。
與模板上的 v-if 類似,你也可以在 template 標籤上使用 v-for 來渲染一個包含多個元素的塊。例如:
<ul>
<template v-for="item in items">
<li>{{ item.msg }}</li>
<li class="divider" role="presentation"></li>
</template>
</ul>
注意!!!
同時使用 v-if 和 v-for 是不推薦的,因為這樣二者的優先級不明顯。
當它們同時存在於一個節點上時,v-if 比 v-for 的優先級更高。這意味著 v-if 的條件將無法訪問到 v-for 作用域內定義的變量別名:
<!--
這會拋出一個錯誤,因為屬性 todo 此時
沒有在該實例上定義
-->
<li v-for="todo in todos" v-if="!todo.isComplete">
{{ todo.name }}
</li>
在外先封装一層 template 再在其上使用 v-for 可以解決這個問題 (這也更加明顯易讀):
<template v-for="todo in todos">
<li v-if="!todo.isComplete">
{{ todo.name }}
</li>
</template>